package com.chuangyiruanke.util;

import com.sun.istack.internal.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class DotMatrixHelper {
    private DotMatrixFont gb2312;
    private DotMatrixFont ascii;

    private static DotMatrixHelper current;

    public static DotMatrixHelper getCurrent() {
        if (current == null) {
            try {
                current = new DotMatrixHelper();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return current;
    }

    public DotMatrixHelper() throws IOException {
        gb2312 = new DotMatrixFont("HZK16C", 16, 16);
        ascii = new DotMatrixFont("ASC16", 8, 16);
    }

    @SuppressWarnings("unused")
    @NotNull
    public BitArray getColumnMatrix(@NotNull String text, @NotNull RefValue<Integer> rowNum) {
        List<MatrixInfo> matrixInfos = getMatrix(text);
        return toColumnMatrix(matrixInfos, rowNum);
    }

    @SuppressWarnings("unused")
    @NotNull
    public BitArray getRowMatrix(@NotNull String text, @NotNull RefValue<Integer> colNum) {
        List<MatrixInfo> matrixInfos = getMatrix(text);
        return toRowMatrix(matrixInfos, colNum);
    }

    @NotNull
    private List<MatrixInfo> getMatrix(@NotNull String text) {
        List<MatrixInfo> matrixInfos = new ArrayList<>();
        try {
            byte[] bytes = text.getBytes("GBK");

            for (int i = 0; i < bytes.length; i++) {
                MatrixInfo info = new MatrixInfo();
                if (bytes[i] > 0xa0) {
                    byte[] codec = new byte[]{bytes[i], bytes[i + 1]};
                    info.codec = gb2312.getGBKMatrix(codec);
                    info.colNum = gb2312.getWidth();
                    info.rowNum = gb2312.getHeight();
                    i++;
                } else {
                    info.codec = ascii.getAsciiMatrix(bytes[i]);
                    info.colNum = ascii.getWidth();
                    info.rowNum = ascii.getHeight();
                }
                matrixInfos.add(info);
            }
        } catch (Exception ex) {
        }
        return matrixInfos;
    }

    /**
     * 按从左到右从上到下的顺序返回点阵信息
     *
     * @param list
     * @param colNum 矩阵中包含的列数
     * @return
     */
    @NotNull
    private BitArray toRowMatrix(List<MatrixInfo> list, @NotNull RefValue<Integer> colNum) {
        int maxRowNum = 0;
        colNum.value = 0;
        if (list.size() == 0) {
            return new BitArray();
        }
        for (MatrixInfo info : list) {
            colNum.value += info.colNum;
            maxRowNum = Math.max(maxRowNum, info.rowNum);
        }
        byte[] values = new byte[maxRowNum * colNum.value];
        for (int row = 0; row < maxRowNum; row++) {
            for (MatrixInfo info : list) {
                int startIndex = row * info.colNum;
                if (info.codec.length > startIndex && info.codec.length < startIndex + info.colNum) {
                    System.arraycopy(info.codec, row * info.colNum,
                            values, row * colNum.value, info.colNum >> 3);
                }
            }
        }

        return new BitArray(values);
    }

    /**
     * 按从上到下从左到右的顺序返回点阵信息 上下为行 左右为列
     *
     * @param list
     * @param rowNum 矩阵中包含的行数
     * @return
     */
    @NotNull
    private BitArray toColumnMatrix(List<MatrixInfo> list, @NotNull RefValue<Integer> rowNum) {
        int colNum = 0;
        rowNum.value = 0;
        if (list.size() == 0) {
            return new BitArray();
        }
        for (MatrixInfo info : list) {
            colNum += info.colNum;
            rowNum.value = Math.max(rowNum.value, info.rowNum);
        }

        int currentMatrixIndex = -1;
        int currentMaxCol = 0;
        MatrixInfo current = null;

        BitArray result = new BitArray(colNum * rowNum.value);
        for (int col = 0; col < colNum; col++) {
            if (col >= currentMaxCol) {
                currentMatrixIndex += 1;
                current = list.get(currentMatrixIndex);
                currentMaxCol += current.colNum;
            }
            int destOffset = col * rowNum.value;
            for (int row = 0; row < rowNum.value; row++) {
                int srcIndex = (row * current.colNum) + col;
                int val = current.codec[srcIndex >> 3] & 0xff;
                result.set(destOffset + row, (val & (0x80 >> (col & 0x7))) != 0);
            }
        }

        return result;
    }

    private static class MatrixInfo {
        byte[] codec;
        int colNum;
        int rowNum;
    }
}
